package com.rfid.uhf;

import android.util.Log;

import com.BRMicro.SerialPort;
import com.uhf.api.cls.Reader;
import com.uhf.api.cls.Reader.AntPower;
import com.uhf.api.cls.Reader.AntPowerConf;
import com.uhf.api.cls.Reader.Lock_Obj;
import com.uhf.api.cls.Reader.Lock_Type;
import com.uhf.api.cls.Reader.Mtr_Param;
import com.uhf.api.cls.Reader.READER_ERR;
import com.uhf.api.cls.Reader.TAGINFO;
import com.uhf.api.cls.Reader.TagFilter_ST;

import java.util.ArrayList;
import java.util.List;

public class UhfReader implements IUhfReader {

	private Reader reader;
	private SerialPort mSerialport;

	private static UhfReader mUhfreader;

	/* 数据区 */
	public final static int MEMBANK_RESEVER = 0;
	public final static int MEMBANK_EPC = 1;
	public final static int MEMBANK_TID = 2;
	public final static int MEMBANK_USER = 3;
	/* 锁定区 */
	public final static int LOCK_MEM_KILL = 0;
	public final static int LOCK_MEM_ACCESS = 1;
	public final static int LOCK_MEM_EPC = 2;
	public final static int LOCK_MEM_TID = 3;
	public final static int LOCK_MEM_USER = 4;
	/* 锁定类型 */
	public final static int UNLOCK = 0;
	public final static int LOCK_PSD = 2;
	public final static int LOCK_PERM = 4;

	// public static int LOCK_MEM_ACCESS = JniModuleAPI.

	public UhfReader(String serialPath, int port) throws Exception {
		reader = new Reader();
		mSerialport = new SerialPort();
		mSerialport.zigbeepoweron();
		mSerialport.rfidPoweron();
		mSerialport.switch2Channel(port);
		READER_ERR er = reader.InitReader_Notype(serialPath, 1);
		if (er != READER_ERR.MT_OK_ERR) {
			throw new Exception("init device fail");
		}
	}

	// 单例模式
	public static UhfReader getInstance(String serialPath, int port)
			throws Exception {
		if (mUhfreader == null) {
			mUhfreader = new UhfReader(serialPath, port);
		}
		return mUhfreader;
	}

	@Override
	public void close() {
		debugLog("close()");
		if (mUhfreader != null) {
			mUhfreader = null;
			reader.CloseReader();
			mSerialport.zigbeepoweroff();
			mSerialport.rfidPoweroff();

		}

	}

	private int[] ants = new int[] { 1 };
	private short timeout = 50;
	private int[] tagcnt = new int[] { 0 };
	private int ant = 1; // 天线

	/**
	 * 盘存标签
	 */
	@Override
	public List<String> inventoryTag() {
		List<String> list = null;
		READER_ERR er = reader.TagInventory_Raw(ants, ants.length, timeout,
				tagcnt);
		if (er == READER_ERR.MT_OK_ERR) {
			if (tagcnt[0] > 0) {// 盘存到数据
				list = new ArrayList<String>();
				for (int i = 0; i < tagcnt[0]; i++) {
					TAGINFO tagInfo = reader.new TAGINFO();
					er = reader.GetNextTag(tagInfo);// 获取标签数据
					if (er == READER_ERR.MT_OK_ERR) {
						list.add(reader.bytes_Hexstr(tagInfo.EpcId));
					}
				}
			}
		}
		return list;
	}

	@Override
	public void open(String serial, int port) {
		// TODO Auto-generated method stub

	}

	/**
	 * 选择需操作的标签
	 */
	@Override
	public boolean selectEPC(byte[] epc) {
		TagFilter_ST tfst = reader.new TagFilter_ST();
		tfst.bank = 1;
		tfst.fdata = epc;
		tfst.flen = epc.length;
		tfst.isInvert = 0;
		tfst.startaddr = 32;
		// TagFilter_ST tfst2 = reader.new TagFilter_ST();
		READER_ERR er = reader.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, tfst);
		// er = reader.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, tfst2);
		if (er == READER_ERR.MT_OK_ERR) {
			return true;
		}
		return false;
	}

	@Override
	public boolean clearSelect() {
		READER_ERR er = reader.ParamSet(Mtr_Param.MTR_PARAM_TAG_FILTER, null);
		return false;
	}

	private short WRtimeout = 1000;

	@Override
	public byte[] readData(int memBank, int start, int length, byte[] password) {

		byte[] data = new byte[2 * length];
		READER_ERR er = reader.GetTagData(ant, (char) memBank, start, length,
				data, password, WRtimeout);
		if (er == READER_ERR.MT_OK_ERR) {
			return data;
		}
		return null;
	}

	private void debugLog(String msg) {
		Log.d("UHF READER", msg);
	}

	/**
	 * 写数据
	 */
	@Override
	public boolean writeData(int memBank, int start, byte[] password,
			byte[] wData) {
		/**
		 * * READER_ERR WriteTagData(int ant,char bank,int address, byte[] data,
		 * int datalen, byte[] accesspasswd,short timeout); ant 操作的单天线 bank 表示区域
		 * 0表示保留区 1表示epc区 2表示tid区 3表示user区 address 表示地址块， 注意epc区从第二块开始 data 写的数据
		 * datalen 表示写的数据长度 accesspwd 表示密码，默认"00000000" 8个十六进制字符 timeout 操作超时时间
		 */

		READER_ERR er = reader.WriteTagData(ant, (char) memBank, start, wData,
				wData.length, password, WRtimeout);
		if (er == READER_ERR.MT_OK_ERR) {
			return true;
		}
		return false;
	}

	/**
	 * 设置新EPC
	 */
	@Override
	public boolean writeEPC(byte[] newEPC, byte[] password) {
		READER_ERR er = reader.WriteTagEpcEx(ant, newEPC, newEPC.length,
				password, WRtimeout);
		if (er == READER_ERR.MT_OK_ERR) {
			return true;
		}
		return false;
	}

	/**
	 * 修改访问密码
	 */
	@Override
	public boolean writeAccess(byte[] newAccess, byte[] oldAccess) {
		READER_ERR er = reader.WriteTagData(ant,
				(char) UhfReader.MEMBANK_RESEVER, 2, newAccess,
				newAccess.length, oldAccess, WRtimeout);
		if (er == READER_ERR.MT_OK_ERR) {
			return true;
		}
		return false;
	}

	/**
	 * 修改销毁密码
	 */
	@Override
	public boolean writeKillPsd(byte[] newKill, byte[] access) {
		READER_ERR er = reader.WriteTagData(ant,
				(char) UhfReader.MEMBANK_RESEVER, 0, newKill, newKill.length,
				access, WRtimeout);
		if (er == READER_ERR.MT_OK_ERR) {
			return true;
		}
		return false;
	}

	@Override
	public boolean lockTag(int lockType, int lockMem, byte[] access) {
		Lock_Obj lockobj = Lock_Obj.LOCK_OBJECT_ACCESS_PASSWD;
		Lock_Type mlocktype = Lock_Type.ACCESS_PASSWD_UNLOCK;
		switch (lockMem) {
		case LOCK_MEM_ACCESS://访问密码
			lockobj = Lock_Obj.LOCK_OBJECT_ACCESS_PASSWD;
//			lockobj = 0x02;
			if (lockType == LOCK_PERM) {
				mlocktype = Lock_Type.ACCESS_PASSWD_PERM_LOCK;
//				mlocktype = (byte) 0xC0 ;
			} else if (lockType == LOCK_PSD) {
				mlocktype = Lock_Type.ACCESS_PASSWD_LOCK;
//				mlocktype = (byte) 0x80 ;
			} else {
				mlocktype = Lock_Type.ACCESS_PASSWD_UNLOCK;
//				mlocktype = (byte) 0x00 ;
			}
			break;
		case LOCK_MEM_KILL://销毁密码
			lockobj = Lock_Obj.LOCK_OBJECT_KILL_PASSWORD;
//			lockobj = 0x01;
			if (lockType == LOCK_PERM) {
				mlocktype = Lock_Type.KILL_PASSWORD_PERM_LOCK;
//				mlocktype = (byte) 0x0300 ;
			} else if (lockType == LOCK_PSD) {
				mlocktype = Lock_Type.KILL_PASSWORD_LOCK;
//				mlocktype = (byte) 0x0200 ;
			} else {
				mlocktype = Lock_Type.KILL_PASSWORD_UNLOCK;
//				mlocktype = (byte)  0x0000  ;
			}
			break;
		case LOCK_MEM_EPC://EPC
			lockobj = Lock_Obj.LOCK_OBJECT_BANK1;
//			lockobj = 0x04;
			if (lockType == LOCK_PERM) {
				mlocktype = Lock_Type.BANK1_PERM_LOCK;
//				mlocktype = (byte) 0x30;
			} else if (lockType == LOCK_PSD) {
				mlocktype = Lock_Type.BANK1_LOCK;
//				mlocktype = (byte) 0x20 ;
			} else {
				mlocktype = Lock_Type.BANK1_UNLOCK;
//				mlocktype = (byte) 0x00 ;
			}
			break;
		case LOCK_MEM_TID://
			lockobj = Lock_Obj.LOCK_OBJECT_BANK2;
//			lockobj = 0x08;
			if (lockType == LOCK_PERM) {
				mlocktype = Lock_Type.BANK2_PERM_LOCK;
//				mlocktype = (byte) 0x0C ;
			} else if (lockType == LOCK_PSD) {
				mlocktype = Lock_Type.BANK2_LOCK;
//				mlocktype = (byte) 0x08 ;
			} else {
				mlocktype = Lock_Type.BANK2_UNLOCK;
//				mlocktype = (byte) 0x00 ;
			}
			break;
		case LOCK_MEM_USER:
			lockobj = Lock_Obj.LOCK_OBJECT_BANK3;
//			lockobj = 0x10;/
			if (lockType == LOCK_PERM) {
				mlocktype = Lock_Type.BANK3_PERM_LOCK;
//				mlocktype = (byte) 0x03 ;
			} else if (lockType == LOCK_PSD) {
				mlocktype = Lock_Type.BANK3_LOCK;
//				mlocktype = (byte) 0x02 ;
			} else {
				mlocktype = Lock_Type.BANK3_UNLOCK;
//				mlocktype = (byte) 0x00 ;
			}
			break;

		}
		
		READER_ERR er = reader.LockTag(ant, (byte)lockobj.value(), (short)mlocktype.value(), access, WRtimeout);
		if(er == READER_ERR.MT_OK_ERR){
			return true ;
		}
		return false;
	}

	/**
	 * 设置输出功率
	 */
	@Override
	public boolean setOutPower(short value) {
		AntPowerConf apcf=reader.new AntPowerConf();
		apcf.antcnt = 1;
		AntPower jaap=reader.new AntPower();
		jaap.antid=1;
		jaap.readPower=value;
		jaap.writePower=value;
		apcf.Powers[0]=jaap;
		READER_ERR er = reader.ParamSet(Mtr_Param.MTR_PARAM_RF_ANTPOWER, apcf);
		if(er == READER_ERR.MT_OK_ERR){
			return true ;
		}
		return false;
	}

}
